//
//  LDSprite.h
//  
//
//  Created by snowymydog on 29/05/10.
//  Copyright LazyDog 2010. All rights reserved.
//

#import "LDSprite.h"
#import <OpenGLES/ES1/glext.h>
#import "OpenGL_Internal.h"
//#import <UIKit/UIKit.h>
//#import "EAGLView.h"

@implementation LDSprite

@synthesize _name;
@synthesize _spritesheetWidth, _spritesheetHeight;
@synthesize _size;

//@synthesize	key;
@synthesize	tileWidth;
@synthesize	tileHeight;
@synthesize	tileInterval;
@synthesize	tileTimer;
@synthesize	startTile;
@synthesize	endTile;
@synthesize nowTile;
@synthesize tileRepeat;
@synthesize movesInterval, movesTimer;
@synthesize startX, endX, nowX, movesIncX;
@synthesize startY, endY, nowY, movesIncY;
@synthesize extendXY, movesRepeat;
@synthesize distantX, distantY;
@synthesize distantRatio;
@synthesize drawMe;

- (id) makeSpriteFromSprite : (LDSprite *) source {
			
	// 設定各個variables
	_spritesheetWidth	= source._spritesheetWidth;
	_spritesheetHeight	= source._spritesheetHeight;
	_name	= source._name;
	_size	= source._size;	
	[self setClip:0 :0 :_size.width :_size.height];
	
	strcpy(key, [source spriteKey]);
	//key				= [NSString stringWithString : source.key];
	tileWidth		= source.tileWidth;
	tileHeight		= source.tileHeight;
	tileInterval	= source.tileInterval;
	tileTimer		= source.tileTimer;
	startTile		= source.startTile;
	endTile			= source.endTile;
	nowTile			= source.nowTile;
	[self setTile:nowTile]; 
	tileRepeat		= source.tileRepeat;
	movesInterval	= source.movesInterval;
	movesTimer		= source.movesTimer;
	startX = nowX	= source.startX;		// 留意將nowX在這裡會自動設定好
	startY = nowY	= source.startY;		// 留意將nowY在這裡會自動設定好
	endX			= source.endX;
	endY			= source.endY;
	extendXY		= source.extendXY;
	movesIncX		= source.movesIncX;
	movesIncY		= source.movesIncY;
	movesRepeat		= source.movesRepeat;
	drawMe			= source.drawMe;
			
	// 如果在程式中更改了sprite中的startX, startY, endX, endY, movesIncX或movesIncY
	// 就必須要執行一次calDistantRatio這個method，否則sprite在斜線移動時便不會依正確路線
	[self calcDistantRatio];
	return self;
}

- (void) linkSpritesheet : (Texture2D *) spriteSheet {

	_spritesheetWidth	= [spriteSheet pixelsWide];
	_spritesheetHeight	= [spriteSheet pixelsHigh];
	_name	= [spriteSheet name];
	_size	= [spriteSheet contentSize];	
	[self setClip:0 :0 :_size.width :_size.height];
		
}

- (void) drawClipAtPoint:(CGPoint)point
{
	GLfloat halfX = tileWidth / 2;
	GLfloat halfY = tileHeight / 2;
	
	GLfloat _minU = _clipX/_spritesheetWidth;
	GLfloat _maxU = (_clipX+tileWidth)/_spritesheetWidth;
	GLfloat _minV = _clipY/_spritesheetHeight;
	GLfloat _maxV = (_clipY+tileHeight)/_spritesheetHeight;

	GLfloat	coordinates[] =	// 這部份擷取整張texture的那一部份做sprite 
	{
		_minU,	_maxV,
		_maxU,	_maxV,
		_minU,	_minV,
		_maxU,	_minV
	};

	GLfloat	xx = - tileWidth/2;
	GLfloat yy = - tileHeight/2;

	GLfloat	vertices[] = 
	{
		xx,				yy,				
		xx+tileWidth,	yy,				
		xx,				yy+tileHeight,
		xx+tileWidth,	yy+tileHeight	
	};
	
	glBindTexture(GL_TEXTURE_2D, _name);
	glPushMatrix();
	glTranslatef(point.x+halfX, 480-point.y+halfY-tileHeight, 0.0f);	// 用480減y，便可以令原本Y的0點在最下方，改成在最上方
															// halfX及halfY是半格sprite的長度
															// 用以將原本sprite以中心點為座標，改為以左上角做座標
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	glPopMatrix();
}

// 設定一個frame的clipping region
// clipX, clipY是 clipping region在spritesheet上的起始位置（左上角為源點）
// clipWidth, clipHeight是一個frame的闊度及高度
- (void) setClip: (CGFloat) clipX:(CGFloat) clipY:(CGFloat)clipWidth:(CGFloat)clipHeight
{
	_clipX = clipX;
	_clipY = clipY;
	tileWidth = clipWidth;
	tileHeight = clipHeight;
} // setClip

// 一張spritesheet可以包含多格tile
// setTile計算出指定的tile在spritesheet中的起始位置
// tile數是由0開始算起，即第一格是tile 0，第二格是tile 1等如此類推
//  一張spritesheet由多個tile構成，tile順序由上至下，由左至右排列
// 行及列的數量不限，但spritesheet必須在1024x1024之內
- (void) setTile: (int) tile {
	
	int x, y;	// 運算時必須以整數計算，否則出來的座標便不正確
	
	x = tileWidth * tile;			//先假設spritesheet是一整條橫條，並計算出frame的位置
	y = x / _size.width;			//再計算有多少行sprite
	x = x - (y * _size.width);	//利用巳找出的行數修正x
	y = y * tileHeight;				//行數*一個frame的高度便是y的正確位置
	_clipX = x;
	_clipY = y;

} // setFrame

- (void)animateSprite {
	// upate所有timer
	tileTimer++;
	movesTimer++;
	
	// 自動化的tile切換
	if (tileTimer > tileInterval) {
		if (nowTile == endTile) {
			if (tileRepeat == YES)
				nowTile = startTile;
		}
		else {
			nowTile++;
		}

		[self setTile:nowTile];
		tileTimer = 0;	// 重設timer
	}
	
/*	// sprite走出了屏幕，如果沒有設定成repeat便不render
	if ([self isOnScreen] == NO) {
		if (movesRepeat == YES) {
			// 重設回開始座標
			nowX = startX;
			nowY = startY;
			//[self calcDistantRatio];
		}
		else
			return;
	}
*/		
	// 自動移動sprite
	if (movesTimer < movesInterval) {		// 還沒有到要update的時侯
		return;
	}
	// 重設timer
	movesTimer = 0;
	
	if ((nowX == endX) && (nowY == endY)) { // 經已到達目標地點
		if (movesRepeat == YES) {			// 設定了自動重覆移動
			nowX = startX;					// 重設到開始地點
			nowY = startY;
		}
		return;
	}

	// 這部份處理橫向的sprite移動	
	if (nowX != endX) {
		if (nowX < endX) {					// 由畫面左方移至右方
		//	nowX += movesIncX;				// 移動經預設好的距離
		//	if (nowX > endX) {				// 如果超出目的地，就設定為目的地
		//		nowX = endX;
		//	}
			
			if (abs(distantY) > abs(distantX)) {		// y-axis needs run longer
			/*	runFrac = (float)modf((float)distantRatio, &runInt);
				nowX = nowX + runInt;
				runLength += runFrac;
				if (runLength > 1) {
					nowX++;
					runLength = runLength -1;
				} */
				nowX = nowX + distantRatio;
			}
			else {
				nowX += movesIncX;
			}
			if (nowX > endX) {
				nowX = endX;
			}
		}
		else {								// 由畫面右方移至左方
			//nowX -= movesIncX;				// 移動經預設好的距離
			//if (nowX < endX) {				// 如果超出目的地，就設定為目的地
			//	nowX = endX;
			//}
			if (abs(distantY) > abs(distantX)) {
			/*	runFrac = (float)modf((float)distantRatio, &runInt);
				nowX = nowX - runInt;
				runLength += runFrac;
				if (runLength > 1) {
					nowX--;
					runLength = runLength -1;
				} */
			nowX = nowX - distantRatio;
			}
			else {
				nowX -= movesIncX;
			}
			if (nowX < endX) {
				nowX = endX;
			}
		}
	}
	
	// 這部份處理縱向的sprite移動
	if (nowY != endY) {	
		if (nowY < endY) {					// 由畫面上方移至下方
			//nowY += movesIncY;				// 移動經預設好的距離
			//if (nowY > endY) {				// 如果超出目的地，就設定為目的地
			//	nowY = endY;
			//}
			if (abs(distantX) > abs(distantY)) {		// y-axis needs run longer
			/*	runFrac = modf(distantRatio, &runInt);
				nowY = nowY + ((int)runInt);
				runLength += runFrac;
				if (runLength > 1.0) {
					nowY++;
					runLength = runLength -1.0;
				}*/
				nowY = nowY + distantRatio;
			}
			else {
				nowY += movesIncY;
				//nowY = nowY;
			}
			if (nowY > endY) {
				nowY = endY;
			}
		}
		else {								// 由畫面下方移至上方
			//nowY -= movesIncY;				// 移動經預設好的距離
			//if (nowY < endY) {				// 如果超出目的地，就設定為目的地
			//	nowY = endY;	
			//}
			if (abs(distantX) > abs(distantY)) {
			/*	runFrac = (float)modf((float)distantRatio, &runInt);
				nowY = nowY - runInt;
				runLength += runFrac;
				if (runLength > 1) {
					nowY--;
					runLength = runLength -1;
				}
			 */
			nowY = nowY - distantRatio;
			}
			else {
				nowY -= movesIncY;
			}
			if (nowY < endY) {
				nowY = endY;	
			}
		}
	}	
} // animateSprite

// 這個method是要修正sprite在斜線移動時的值
// lazyDog2D的sprite主要由movesIncX及moveIncY控制，如果單純只由這兩個variables去工作，
// 便無法使x及y同時到達目的座標
- (void) calcDistantRatio {
	
	// 先計算出橫向及縱向各自需要的移動距離
	distantX = abs(endX - nowX);
	distantY = abs(endY - nowY);
	
	distantRatio = 0.0;
	
	// 這裡會視乎那一個方向的行進距離較短，去計算出distant ratio
	// 只有距離較短的那一個方向需要修正
	if (distantX > distantY) {
		if (distantX) {			// make sure not divide by zero
			distantRatio = ((double)distantY / (double)distantX) * movesIncY;
		}
	} else if (distantY > distantX) {
		if (distantY) {		// make sure not divide by zero
			distantRatio = ((double)distantX / (double)distantY) * movesIncX;
		}
	}

} // calcDistantRatio

// extendXY會將原來的endX, endY延伸至屏幕外而保持路線的角度不變
- (void) extendEndXY {
	float ratio;
	float  newX, newY;
	float newDistantX;
	
	// 算出緃及橫的比例
	
	// 先計算出緃橫的長度

	distantX = abs(endX - nowX);
	distantY = abs(endY - nowY);	
	if (endX > nowX) {	// left to right
		newX = 320.0;
		newDistantX = fabs(newX - nowX);
	}	
	else {
		newX = 0.0 - tileWidth;
		newDistantX = fabs(nowX - newX);
	}
	
	ratio = newDistantX / distantX;
	
	if (startY > endY)
		newY = startY - (distantY * ratio);
	else
		newY = startY + (distantY * ratio);
			
	endX = newX;
	endY = newY;
	[self calcDistantRatio];
}

- (BOOL) isOnScreen {
	CGRect scrRect, spriteRect;
	
	scrRect		= CGRectMake(0.0,0.0,320.0,480.0);
	spriteRect	= CGRectMake(nowX,nowY,tileWidth,tileHeight);
	
	return CGRectIntersectsRect(scrRect, spriteRect);
}

- (void) setStartXY :(float) x : (float) y {
	startX = x;
	startY = y;
}

- (void) setNowXY : (float) x : (float) y {
	nowX = x;
	nowY = y;
}

- (void) setEndXY :(float) x : (float) y {
	endX = x;
	endY = y;
}

- (void) setDrawMe : (BOOL) yesno {
	drawMe = yesno;
}

- (void) reset {
	nowX = endX;
	nowY = endY;
	[self calcDistantRatio];
}

- (void) setSpriteKey : (char *) skey {
	strcpy(key, skey);
}

- (char *) spriteKey {
	return key;
}

- (BOOL) drawMeFlag {
	return drawMe;
}

- (void)dealloc {
//	[window release];
//	[glView release];
	[super dealloc];
}

@end
